package com.msh.starter.common.base;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.msh.frame.client.base.BasePo;
import com.msh.frame.client.base.BaseQo;
import com.msh.frame.client.base.BaseServiceImpl;
import com.msh.frame.client.common.Result;
import com.msh.frame.interfaces.ICache;
import com.msh.frame.interfaces.ICacheManager;
import com.msh.starter.common.instance.ApplicationContextUtil;

import java.util.*;

/**
 * @author shihu 带缓存的serviceImpl 永久缓存单条信息和list信息，分页信息都缓存 一些数量少且修改非常少的数据可以使用 虽然是永久缓存，但还是设置了过期时间30天
 * 防止不使用之后redis一直占用内存
 */
public abstract class BasePermanentCacheServiceImpl<T extends BasePo, Q extends BaseQo> extends
    BaseServiceImpl<T, Q> {

  protected ICache<String, Object> cache;
  /**
   * 单条查询缓存
   */
  final private static String GET_PREFIX = "get:";
  /**
   * 列表缓存
   */
  final private static String LIST_PREFIX = "list:";
  /**
   * 列表缓存
   */
  final private static String PAGE_PREFIX = "page:";
  /**
   * 获取列表查询单条信息缓存
   */
  final private static String LIST_ONE_PREFIX = "list_one:";
  /**
   * 查询条数缓存
   */
  final private static String COUNT_PREFIX = "count:";
  /**
   * 非空值过期时间
   */
  final private static long NO_NULL_EXPIRE_SECOND = 30 * 24 * 60 * 60L;
  /**
   * 空值过期时间
   */
  final private static long NULL_EXPIRE_SECOND = 300L;

  @Override
  public T get(Long id) {
    String key = GET_PREFIX + id;
    T t = (T) getCache().get(key);
    if (null == t) {
      t = super.get(id);
      if (null != t) {
        getCache().put(key, t, NO_NULL_EXPIRE_SECOND);
      } else {
        getCache().put(key, t, NULL_EXPIRE_SECOND);
      }
    }
    return t;
  }

  @Override
  public void update(T param) {
    String key = GET_PREFIX + param.getId();
    getCache().remove(key);
    clearListCountCache();
    super.update(param);
  }

  @Override
  public int delete(Long id) {
    String key = GET_PREFIX + id;
    getCache().remove(key);
    clearListCountCache();
    return super.delete(id);
  }

  @Override
  public long insert(T param) {
    String key = GET_PREFIX + param.getId();
    getCache().remove(key);
    clearListCountCache();
    return super.insert(param);
  }

  @Override
  public int insertCollection(Collection param) {
    Set<String> set = new HashSet<>();
    Iterator it = param.iterator();
    while (it.hasNext()) {
      T t = (T) it.next();
      set.add(GET_PREFIX + t.getId());
    }
    getCache().remove(set);
    clearListCountCache();
    return super.insertCollection(param);
  }


  private void clearListCountCache() {
    getCache().clearPrefix(LIST_PREFIX);
    getCache().clearPrefix(LIST_ONE_PREFIX);
    getCache().clearPrefix(COUNT_PREFIX);
  }

  @Override
  public List<T> list(Q param) {
    String key = LIST_PREFIX + JSON.toJSONString(param);
    List<T> list = (List<T>) getCache().get(key);
    if (null == list) {
      list = super.list(param);
      getCache().put(key, list, NO_NULL_EXPIRE_SECOND);
    }
    return list;
  }

  @Override
  public Result<List<T>> page(Q param) {
    String key = PAGE_PREFIX + JSON.toJSONString(param);
    Result<List<T>> result = (Result<List<T>>) getCache().get(key);
    if (null == result) {
      result = super.page(param);
      if (0 == result.getCode()) {
        getCache().put(key, result, NO_NULL_EXPIRE_SECOND);
        String paramStr = JSON.toJSONString(param);
        JSONObject jsonObject = JSON.parseObject(paramStr);
        jsonObject.remove("firstRow");
        jsonObject.remove("currentPage");
        jsonObject.remove("pageSize");
        String countKey = COUNT_PREFIX + jsonObject.toJSONString();
        getCache().put(countKey, result.getCount(), NO_NULL_EXPIRE_SECOND);
      }
    }
    return result;
  }

  @Override
  public T listOne(Q param) {
    String key = LIST_ONE_PREFIX + JSON.toJSONString(param);
    T t = (T) getCache().get(key);
    if (null == t) {
      t = super.listOne(param);
      getCache().put(key, t, NO_NULL_EXPIRE_SECOND);
    }
    return t;
  }

  @Override
  public int count(Q param) {
    String key = COUNT_PREFIX + JSON.toJSONString(param);
    Integer count = (Integer) getCache().get(key);
    if (null == count) {
      count = super.count(param);
      getCache().put(key, count, NO_NULL_EXPIRE_SECOND);
    }
    return super.count(param);
  }

  public ICache<String, Object> getCache() {
    if (null == cache) {
      cache = ApplicationContextUtil.getBean(ICacheManager.class)
          .getCache(this.getClass().getName());
    }
    return cache;
  }

}
